{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 数据预处理"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/malele/anaconda3/lib/python3.6/site-packages/h5py/__init__.py:36: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.\n",
      "  from ._conv import register_converters as _register_converters\n",
      "Using TensorFlow backend.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "X_train shape: (9531, 200, 1, 12)\n",
      "Y_train shape: (9531, 49)\n",
      "X_test shape: (2383, 200, 1, 12)\n",
      "Y_test shape: (2383, 49)\n"
     ]
    }
   ],
   "source": [
    "import h5py\n",
    "import numpy as np\n",
    "import tensorflow as tf \n",
    "import keras\n",
    "from keras.layers import Input, Dense, Dropout, Activation, Flatten, Conv2D, Conv1D, MaxPooling2D, concatenate, BatchNormalization\n",
    "from keras.models import Model\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "\n",
    "def convert_to_one_hot(Y, C):\n",
    "    Y = np.eye(C)[Y.reshape(-1)].T\n",
    "    return Y\n",
    "\n",
    "file = h5py.File('DB2/DB2_S1_image_200_0.h5','r')\n",
    "imageData   = file['imageData'][:]\n",
    "imageLabel  = file['imageLabel'][:]  \n",
    "file.close()\n",
    "\n",
    "# 随机打乱数据和标签\n",
    "N = imageData.shape[0]\n",
    "index = np.random.permutation(N)\n",
    "data  = imageData[index,:,:]\n",
    "label = imageLabel[index]\n",
    "\n",
    "# 对数据升维,标签one-hot\n",
    "data  = np.expand_dims(data, axis=2)\n",
    "label = convert_to_one_hot(label,49).T\n",
    "\n",
    "# 划分数据集\n",
    "N = data.shape[0]\n",
    "num_train = round(N*0.8)\n",
    "X_train = data[0:num_train,:,:]\n",
    "Y_train = label[0:num_train,:]\n",
    "X_test  = data[num_train:N,:,:]\n",
    "Y_test  = label[num_train:N,:]\n",
    "\n",
    "print (\"X_train shape: \" + str(X_train.shape))\n",
    "print (\"Y_train shape: \" + str(Y_train.shape))\n",
    "print (\"X_test shape: \" + str(X_test.shape))\n",
    "print (\"Y_test shape: \" + str(Y_test.shape))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "#写一个LossHistory类，保存loss和acc\n",
    "class LossHistory(keras.callbacks.Callback):\n",
    "    def on_train_begin(self, logs={}):\n",
    "        self.losses = {'batch':[], 'epoch':[]}\n",
    "        self.accuracy = {'batch':[], 'epoch':[]}\n",
    "        self.val_loss = {'batch':[], 'epoch':[]}\n",
    "        self.val_acc = {'batch':[], 'epoch':[]}\n",
    "\n",
    "    def on_batch_end(self, batch, logs={}):\n",
    "        self.losses['batch'].append(logs.get('loss'))\n",
    "        self.accuracy['batch'].append(logs.get('acc'))\n",
    "        self.val_loss['batch'].append(logs.get('val_loss'))\n",
    "        self.val_acc['batch'].append(logs.get('val_acc'))\n",
    "\n",
    "    def on_epoch_end(self, batch, logs={}):\n",
    "        self.losses['epoch'].append(logs.get('loss'))\n",
    "        self.accuracy['epoch'].append(logs.get('acc'))\n",
    "        self.val_loss['epoch'].append(logs.get('val_loss'))\n",
    "        self.val_acc['epoch'].append(logs.get('val_acc'))\n",
    "\n",
    "    def loss_plot(self, loss_type):\n",
    "        iters = range(len(self.losses[loss_type]))\n",
    "        plt.figure()\n",
    "        # acc\n",
    "        plt.plot(iters, self.accuracy[loss_type], 'r', label='train acc')\n",
    "        # loss\n",
    "        plt.plot(iters, self.losses[loss_type], 'g', label='train loss')\n",
    "        if loss_type == 'epoch':\n",
    "            # val_acc\n",
    "            plt.plot(iters, self.val_acc[loss_type], 'b', label='val acc')\n",
    "            # val_loss\n",
    "            plt.plot(iters, self.val_loss[loss_type], 'k', label='val loss')\n",
    "        plt.grid(True)\n",
    "        plt.xlabel(loss_type)\n",
    "        plt.ylabel('acc-loss')\n",
    "        plt.legend(loc=\"upper right\")\n",
    "        plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 建立模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "_________________________________________________________________\n",
      "Layer (type)                 Output Shape              Param #   \n",
      "=================================================================\n",
      "input_1 (InputLayer)         (None, 200, 1, 12)        0         \n",
      "_________________________________________________________________\n",
      "conv1 (Conv2D)               (None, 200, 1, 32)        7712      \n",
      "_________________________________________________________________\n",
      "pool1 (MaxPooling2D)         (None, 20, 1, 32)         0         \n",
      "_________________________________________________________________\n",
      "conv2 (Conv2D)               (None, 20, 1, 64)         12352     \n",
      "_________________________________________________________________\n",
      "pool2 (MaxPooling2D)         (None, 10, 1, 64)         0         \n",
      "_________________________________________________________________\n",
      "conv3 (Conv2D)               (None, 10, 1, 128)        24704     \n",
      "_________________________________________________________________\n",
      "pool3 (MaxPooling2D)         (None, 5, 1, 128)         0         \n",
      "_________________________________________________________________\n",
      "flatten (Flatten)            (None, 640)               0         \n",
      "_________________________________________________________________\n",
      "dropout_1 (Dropout)          (None, 640)               0         \n",
      "_________________________________________________________________\n",
      "fc1 (Dense)                  (None, 128)               82048     \n",
      "_________________________________________________________________\n",
      "dropout_2 (Dropout)          (None, 128)               0         \n",
      "_________________________________________________________________\n",
      "fc2 (Dense)                  (None, 49)                6321      \n",
      "=================================================================\n",
      "Total params: 133,137\n",
      "Trainable params: 133,137\n",
      "Non-trainable params: 0\n",
      "_________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "def CNN(input_shape=(200,1,12), classes=49): \n",
    "    X_input = Input(input_shape)\n",
    "    \n",
    "    X = Conv2D(filters=32,kernel_size=(20,1),strides=(1,1),padding='same',activation='relu',name='conv1')(X_input)\n",
    "    X = MaxPooling2D(pool_size=(10,1), strides=(10,1), name='pool1')(X)\n",
    "    \n",
    "    X = Conv2D(filters=64,kernel_size=(6,1),strides=(1,1),padding='same',activation='relu',name='conv2')(X)\n",
    "    X = MaxPooling2D(pool_size=(2,1), strides=(2,1), name='pool2')(X)\n",
    "    \n",
    "    X = Conv2D(filters=128,kernel_size=(3,1),strides=(1,1),padding='same',activation='relu',name='conv3')(X)\n",
    "    X = MaxPooling2D(pool_size=(2,1), strides=(2,1), name='pool3')(X)\n",
    "    \n",
    "    X = Flatten(name='flatten')(X)\n",
    "    X = Dropout(0.5)(X)\n",
    "    X = Dense(128,activation='relu',name='fc1')(X)\n",
    "    X = Dropout(0.5)(X)\n",
    "    X = Dense(classes, activation='softmax', name='fc2')(X)\n",
    "    \n",
    "    model = Model(inputs=X_input, outputs=X, name='CNN')\n",
    "    return model\n",
    "model = CNN(input_shape = (200, 1, 12), classes = 49)\n",
    "model.summary()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 训练原始数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Train on 9531 samples, validate on 2383 samples\n",
      "Epoch 1/100\n",
      "9531/9531 [==============================] - 3s 346us/step - loss: 3.8329 - acc: 0.0358 - val_loss: 3.6237 - val_acc: 0.0965\n",
      "Epoch 2/100\n",
      "9531/9531 [==============================] - 3s 268us/step - loss: 3.2860 - acc: 0.1165 - val_loss: 2.7387 - val_acc: 0.2262\n",
      "Epoch 3/100\n",
      "9531/9531 [==============================] - 2s 245us/step - loss: 2.6640 - acc: 0.2200 - val_loss: 2.2518 - val_acc: 0.3139\n",
      "Epoch 4/100\n",
      "9531/9531 [==============================] - 2s 241us/step - loss: 2.3472 - acc: 0.2844 - val_loss: 2.0594 - val_acc: 0.3747\n",
      "Epoch 5/100\n",
      "9531/9531 [==============================] - 2s 247us/step - loss: 2.1294 - acc: 0.3454 - val_loss: 1.8353 - val_acc: 0.4285\n",
      "Epoch 6/100\n",
      "9531/9531 [==============================] - 2s 252us/step - loss: 1.9504 - acc: 0.3962 - val_loss: 1.6872 - val_acc: 0.4885\n",
      "Epoch 7/100\n",
      "9531/9531 [==============================] - 2s 252us/step - loss: 1.7887 - acc: 0.4443 - val_loss: 1.5712 - val_acc: 0.5061\n",
      "Epoch 8/100\n",
      "9531/9531 [==============================] - 2s 252us/step - loss: 1.6697 - acc: 0.4735 - val_loss: 1.4323 - val_acc: 0.5292\n",
      "Epoch 9/100\n",
      "9531/9531 [==============================] - 2s 250us/step - loss: 1.5607 - acc: 0.5116 - val_loss: 1.4064 - val_acc: 0.5552\n",
      "Epoch 10/100\n",
      "9531/9531 [==============================] - 2s 239us/step - loss: 1.4692 - acc: 0.5372 - val_loss: 1.3243 - val_acc: 0.5711\n",
      "Epoch 11/100\n",
      "9531/9531 [==============================] - 2s 245us/step - loss: 1.4146 - acc: 0.5486 - val_loss: 1.2461 - val_acc: 0.6043\n",
      "Epoch 12/100\n",
      "9531/9531 [==============================] - 2s 254us/step - loss: 1.3385 - acc: 0.5698 - val_loss: 1.2394 - val_acc: 0.6030\n",
      "Epoch 13/100\n",
      "9531/9531 [==============================] - 2s 241us/step - loss: 1.2959 - acc: 0.5839 - val_loss: 1.1816 - val_acc: 0.6190\n",
      "Epoch 14/100\n",
      "9531/9531 [==============================] - 2s 240us/step - loss: 1.2629 - acc: 0.5923 - val_loss: 1.1902 - val_acc: 0.6299\n",
      "Epoch 15/100\n",
      "9531/9531 [==============================] - 2s 247us/step - loss: 1.2135 - acc: 0.6131 - val_loss: 1.1281 - val_acc: 0.6408\n",
      "Epoch 16/100\n",
      "9531/9531 [==============================] - 2s 244us/step - loss: 1.1891 - acc: 0.6123 - val_loss: 1.1251 - val_acc: 0.6521\n",
      "Epoch 17/100\n",
      "9531/9531 [==============================] - 2s 242us/step - loss: 1.1396 - acc: 0.6222 - val_loss: 1.0783 - val_acc: 0.6643\n",
      "Epoch 18/100\n",
      "9531/9531 [==============================] - 2s 250us/step - loss: 1.1219 - acc: 0.6302 - val_loss: 1.0559 - val_acc: 0.6685\n",
      "Epoch 19/100\n",
      "9531/9531 [==============================] - 2s 242us/step - loss: 1.0862 - acc: 0.6474 - val_loss: 1.0573 - val_acc: 0.6588\n",
      "Epoch 20/100\n",
      "9531/9531 [==============================] - 2s 242us/step - loss: 1.0603 - acc: 0.6472 - val_loss: 1.0588 - val_acc: 0.6567\n",
      "Epoch 21/100\n",
      "9531/9531 [==============================] - 2s 244us/step - loss: 1.0239 - acc: 0.6670 - val_loss: 1.0114 - val_acc: 0.6760\n",
      "Epoch 22/100\n",
      "9531/9531 [==============================] - 2s 251us/step - loss: 1.0073 - acc: 0.6609 - val_loss: 1.0217 - val_acc: 0.6765\n",
      "Epoch 23/100\n",
      "9531/9531 [==============================] - 2s 247us/step - loss: 0.9893 - acc: 0.6719 - val_loss: 0.9734 - val_acc: 0.6861\n",
      "Epoch 24/100\n",
      "9531/9531 [==============================] - 2s 250us/step - loss: 0.9638 - acc: 0.6746 - val_loss: 1.0365 - val_acc: 0.6630\n",
      "Epoch 25/100\n",
      "9531/9531 [==============================] - 2s 245us/step - loss: 0.9532 - acc: 0.6852 - val_loss: 0.9848 - val_acc: 0.6895\n",
      "Epoch 26/100\n",
      "9531/9531 [==============================] - 2s 245us/step - loss: 0.9154 - acc: 0.6986 - val_loss: 1.0050 - val_acc: 0.6836\n",
      "Epoch 27/100\n",
      "9531/9531 [==============================] - 2s 239us/step - loss: 0.9162 - acc: 0.6984 - val_loss: 0.9285 - val_acc: 0.6995\n",
      "Epoch 28/100\n",
      "9531/9531 [==============================] - 2s 251us/step - loss: 0.8746 - acc: 0.7091 - val_loss: 0.9936 - val_acc: 0.6874\n",
      "Epoch 29/100\n",
      "9531/9531 [==============================] - 2s 257us/step - loss: 0.8640 - acc: 0.7104 - val_loss: 1.0053 - val_acc: 0.6932\n",
      "Epoch 30/100\n",
      "9531/9531 [==============================] - 2s 245us/step - loss: 0.8540 - acc: 0.7108 - val_loss: 0.9141 - val_acc: 0.7084\n",
      "Epoch 31/100\n",
      "9531/9531 [==============================] - 2s 251us/step - loss: 0.8413 - acc: 0.7192 - val_loss: 0.9236 - val_acc: 0.7054\n",
      "Epoch 32/100\n",
      "9531/9531 [==============================] - 2s 248us/step - loss: 0.8094 - acc: 0.7267 - val_loss: 0.8987 - val_acc: 0.7201\n",
      "Epoch 33/100\n",
      "9531/9531 [==============================] - 2s 249us/step - loss: 0.8258 - acc: 0.7271 - val_loss: 0.9220 - val_acc: 0.7117\n",
      "Epoch 34/100\n",
      "9531/9531 [==============================] - 2s 243us/step - loss: 0.7978 - acc: 0.7282 - val_loss: 0.8862 - val_acc: 0.7197\n",
      "Epoch 35/100\n",
      "9531/9531 [==============================] - 2s 245us/step - loss: 0.7765 - acc: 0.7325 - val_loss: 0.9452 - val_acc: 0.7029\n",
      "Epoch 36/100\n",
      "9531/9531 [==============================] - 2s 249us/step - loss: 0.7937 - acc: 0.7337 - val_loss: 1.0028 - val_acc: 0.6903\n",
      "Epoch 37/100\n",
      "9531/9531 [==============================] - 2s 245us/step - loss: 0.7646 - acc: 0.7474 - val_loss: 0.8789 - val_acc: 0.7121\n",
      "Epoch 38/100\n",
      "9531/9531 [==============================] - 3s 265us/step - loss: 0.7694 - acc: 0.7365 - val_loss: 0.8814 - val_acc: 0.7138\n",
      "Epoch 39/100\n",
      "9531/9531 [==============================] - 2s 261us/step - loss: 0.7307 - acc: 0.7534 - val_loss: 0.9293 - val_acc: 0.7096\n",
      "Epoch 40/100\n",
      "9531/9531 [==============================] - 2s 247us/step - loss: 0.7473 - acc: 0.7491 - val_loss: 0.8936 - val_acc: 0.7151\n",
      "Epoch 41/100\n",
      "9531/9531 [==============================] - 2s 245us/step - loss: 0.7117 - acc: 0.7523 - val_loss: 0.8951 - val_acc: 0.7180\n",
      "Epoch 42/100\n",
      "9531/9531 [==============================] - 2s 244us/step - loss: 0.7077 - acc: 0.7600 - val_loss: 0.8643 - val_acc: 0.7167\n",
      "Epoch 43/100\n",
      "9531/9531 [==============================] - 2s 251us/step - loss: 0.6910 - acc: 0.7667 - val_loss: 0.8809 - val_acc: 0.7272\n",
      "Epoch 44/100\n",
      "9531/9531 [==============================] - 2s 242us/step - loss: 0.6837 - acc: 0.7658 - val_loss: 0.9494 - val_acc: 0.7180\n",
      "Epoch 45/100\n",
      "9531/9531 [==============================] - 2s 243us/step - loss: 0.6961 - acc: 0.7596 - val_loss: 0.9074 - val_acc: 0.7264\n",
      "Epoch 46/100\n",
      "9531/9531 [==============================] - 2s 245us/step - loss: 0.6620 - acc: 0.7765 - val_loss: 0.8593 - val_acc: 0.7230\n",
      "Epoch 47/100\n",
      "9531/9531 [==============================] - 2s 258us/step - loss: 0.6698 - acc: 0.7707 - val_loss: 0.9047 - val_acc: 0.7251\n",
      "Epoch 48/100\n",
      "9531/9531 [==============================] - 2s 248us/step - loss: 0.6534 - acc: 0.7795 - val_loss: 0.8846 - val_acc: 0.7134\n",
      "Epoch 49/100\n",
      "9531/9531 [==============================] - 2s 250us/step - loss: 0.6454 - acc: 0.7786 - val_loss: 0.9231 - val_acc: 0.7235\n",
      "Epoch 50/100\n",
      "9531/9531 [==============================] - 2s 251us/step - loss: 0.6850 - acc: 0.7646 - val_loss: 0.8564 - val_acc: 0.7298\n",
      "Epoch 51/100\n",
      "9531/9531 [==============================] - 2s 233us/step - loss: 0.6111 - acc: 0.7860 - val_loss: 0.8723 - val_acc: 0.7289\n",
      "Epoch 52/100\n",
      "9531/9531 [==============================] - 2s 236us/step - loss: 0.6132 - acc: 0.7830 - val_loss: 0.9557 - val_acc: 0.7163\n",
      "Epoch 53/100\n",
      "9531/9531 [==============================] - 2s 236us/step - loss: 0.6175 - acc: 0.7887 - val_loss: 0.9173 - val_acc: 0.7188\n",
      "Epoch 54/100\n",
      "9531/9531 [==============================] - 2s 241us/step - loss: 0.6182 - acc: 0.7895 - val_loss: 0.8948 - val_acc: 0.7281\n",
      "Epoch 55/100\n",
      "9531/9531 [==============================] - 2s 235us/step - loss: 0.5957 - acc: 0.7936 - val_loss: 0.9428 - val_acc: 0.7163\n",
      "Epoch 56/100\n",
      "9531/9531 [==============================] - 2s 236us/step - loss: 0.5772 - acc: 0.7991 - val_loss: 0.8953 - val_acc: 0.7293\n",
      "Epoch 57/100\n",
      "9531/9531 [==============================] - 2s 233us/step - loss: 0.5977 - acc: 0.7932 - val_loss: 0.9477 - val_acc: 0.7239\n",
      "Epoch 58/100\n",
      "9531/9531 [==============================] - 2s 234us/step - loss: 0.5825 - acc: 0.7995 - val_loss: 0.8991 - val_acc: 0.7356\n",
      "Epoch 59/100\n",
      "9531/9531 [==============================] - 2s 238us/step - loss: 0.5560 - acc: 0.8090 - val_loss: 0.8980 - val_acc: 0.7386\n",
      "Epoch 60/100\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "9531/9531 [==============================] - 2s 242us/step - loss: 0.5589 - acc: 0.8071 - val_loss: 0.9513 - val_acc: 0.7260\n",
      "Epoch 61/100\n",
      "9531/9531 [==============================] - 2s 234us/step - loss: 0.5512 - acc: 0.8122 - val_loss: 0.8974 - val_acc: 0.7335\n",
      "Epoch 62/100\n",
      "9531/9531 [==============================] - 2s 235us/step - loss: 0.5820 - acc: 0.8018 - val_loss: 0.9391 - val_acc: 0.7289\n",
      "Epoch 63/100\n",
      "9531/9531 [==============================] - 2s 230us/step - loss: 0.5596 - acc: 0.8103 - val_loss: 0.9117 - val_acc: 0.7419\n",
      "Epoch 64/100\n",
      "9531/9531 [==============================] - 2s 234us/step - loss: 0.5520 - acc: 0.8117 - val_loss: 0.9592 - val_acc: 0.7302\n",
      "Epoch 65/100\n",
      "9531/9531 [==============================] - 2s 253us/step - loss: 0.5291 - acc: 0.8169 - val_loss: 0.8936 - val_acc: 0.7289\n",
      "Epoch 66/100\n",
      "9531/9531 [==============================] - 3s 268us/step - loss: 0.5469 - acc: 0.8132 - val_loss: 0.9768 - val_acc: 0.7172\n",
      "Epoch 67/100\n",
      "9531/9531 [==============================] - 2s 249us/step - loss: 0.5177 - acc: 0.8196 - val_loss: 0.9015 - val_acc: 0.7381\n",
      "Epoch 68/100\n",
      "9531/9531 [==============================] - 2s 241us/step - loss: 0.5353 - acc: 0.8143 - val_loss: 0.9265 - val_acc: 0.7344\n",
      "Epoch 69/100\n",
      "9531/9531 [==============================] - 2s 239us/step - loss: 0.5131 - acc: 0.8229 - val_loss: 0.9833 - val_acc: 0.7314\n",
      "Epoch 70/100\n",
      "9531/9531 [==============================] - 2s 239us/step - loss: 0.5099 - acc: 0.8193 - val_loss: 0.9354 - val_acc: 0.7348\n",
      "Epoch 71/100\n",
      "9531/9531 [==============================] - 2s 241us/step - loss: 0.5192 - acc: 0.8205 - val_loss: 0.8969 - val_acc: 0.7411\n",
      "Epoch 72/100\n",
      "9531/9531 [==============================] - 2s 243us/step - loss: 0.5236 - acc: 0.8173 - val_loss: 0.9854 - val_acc: 0.7293\n",
      "Epoch 73/100\n",
      "9531/9531 [==============================] - 2s 236us/step - loss: 0.5112 - acc: 0.8237 - val_loss: 0.9467 - val_acc: 0.7365\n",
      "Epoch 74/100\n",
      "9531/9531 [==============================] - 2s 244us/step - loss: 0.4809 - acc: 0.8358 - val_loss: 0.9586 - val_acc: 0.7348\n",
      "Epoch 75/100\n",
      "9531/9531 [==============================] - 2s 234us/step - loss: 0.5289 - acc: 0.8212 - val_loss: 0.9593 - val_acc: 0.7306\n",
      "Epoch 76/100\n",
      "9531/9531 [==============================] - 2s 233us/step - loss: 0.5156 - acc: 0.8281 - val_loss: 0.9121 - val_acc: 0.7449\n",
      "Epoch 77/100\n",
      "9531/9531 [==============================] - 2s 236us/step - loss: 0.4966 - acc: 0.8286 - val_loss: 0.9556 - val_acc: 0.7310\n",
      "Epoch 78/100\n",
      "9531/9531 [==============================] - 2s 241us/step - loss: 0.4933 - acc: 0.8321 - val_loss: 0.9439 - val_acc: 0.7306\n",
      "Epoch 79/100\n",
      "9531/9531 [==============================] - 2s 237us/step - loss: 0.4927 - acc: 0.8314 - val_loss: 0.9820 - val_acc: 0.7289\n",
      "Epoch 80/100\n",
      "9531/9531 [==============================] - 2s 246us/step - loss: 0.4833 - acc: 0.8332 - val_loss: 0.9186 - val_acc: 0.7440\n",
      "Epoch 81/100\n",
      "9531/9531 [==============================] - 2s 235us/step - loss: 0.4548 - acc: 0.8431 - val_loss: 0.9567 - val_acc: 0.7386\n",
      "Epoch 82/100\n",
      "9531/9531 [==============================] - 2s 239us/step - loss: 0.4695 - acc: 0.8414 - val_loss: 1.0589 - val_acc: 0.7218\n",
      "Epoch 83/100\n",
      "9531/9531 [==============================] - 2s 244us/step - loss: 0.4726 - acc: 0.8355 - val_loss: 0.9743 - val_acc: 0.7235\n",
      "Epoch 84/100\n",
      "9531/9531 [==============================] - 2s 239us/step - loss: 0.4623 - acc: 0.8440 - val_loss: 1.0266 - val_acc: 0.7272\n",
      "Epoch 85/100\n",
      "9531/9531 [==============================] - 2s 234us/step - loss: 0.4700 - acc: 0.8427 - val_loss: 0.9897 - val_acc: 0.7302\n",
      "Epoch 86/100\n",
      "9531/9531 [==============================] - 2s 237us/step - loss: 0.4557 - acc: 0.8445 - val_loss: 1.0215 - val_acc: 0.7272\n",
      "Epoch 87/100\n",
      "9531/9531 [==============================] - 2s 236us/step - loss: 0.4752 - acc: 0.8355 - val_loss: 0.9692 - val_acc: 0.7293\n",
      "Epoch 88/100\n",
      "9531/9531 [==============================] - 2s 243us/step - loss: 0.4520 - acc: 0.8436 - val_loss: 0.9667 - val_acc: 0.7314\n",
      "Epoch 89/100\n",
      "9531/9531 [==============================] - 2s 236us/step - loss: 0.4675 - acc: 0.8428 - val_loss: 1.0533 - val_acc: 0.7180\n",
      "Epoch 90/100\n",
      "9531/9531 [==============================] - 2s 233us/step - loss: 0.4663 - acc: 0.8438 - val_loss: 0.9811 - val_acc: 0.7344\n",
      "Epoch 91/100\n",
      "9531/9531 [==============================] - 2s 239us/step - loss: 0.4693 - acc: 0.8464 - val_loss: 1.0600 - val_acc: 0.7155\n",
      "Epoch 92/100\n",
      "9531/9531 [==============================] - 2s 247us/step - loss: 0.4488 - acc: 0.8449 - val_loss: 1.0934 - val_acc: 0.7235\n",
      "Epoch 93/100\n",
      "9531/9531 [==============================] - 2s 241us/step - loss: 0.4591 - acc: 0.8465 - val_loss: 1.0497 - val_acc: 0.7419\n",
      "Epoch 94/100\n",
      "9531/9531 [==============================] - 2s 236us/step - loss: 0.4559 - acc: 0.8437 - val_loss: 1.0699 - val_acc: 0.7251\n",
      "Epoch 95/100\n",
      "9531/9531 [==============================] - 2s 237us/step - loss: 0.4593 - acc: 0.8448 - val_loss: 1.0773 - val_acc: 0.7214\n",
      "Epoch 96/100\n",
      "9531/9531 [==============================] - 2s 242us/step - loss: 0.4446 - acc: 0.8487 - val_loss: 1.0123 - val_acc: 0.7373\n",
      "Epoch 97/100\n",
      "9531/9531 [==============================] - 2s 233us/step - loss: 0.4159 - acc: 0.8583 - val_loss: 1.0044 - val_acc: 0.7377\n",
      "Epoch 98/100\n",
      "9531/9531 [==============================] - 2s 246us/step - loss: 0.4237 - acc: 0.8562 - val_loss: 1.0476 - val_acc: 0.7327\n",
      "Epoch 99/100\n",
      "9531/9531 [==============================] - 2s 236us/step - loss: 0.4421 - acc: 0.8500 - val_loss: 0.9972 - val_acc: 0.7360\n",
      "Epoch 100/100\n",
      "9531/9531 [==============================] - 2s 236us/step - loss: 0.4486 - acc: 0.8523 - val_loss: 1.0393 - val_acc: 0.7327\n",
      "9531/9531 [==============================] - 1s 146us/step\n",
      "Train Loss = 0.13377866888925544\n",
      "Train Accuracy = 0.9654810617545659\n",
      "2383/2383 [==============================] - 0s 149us/step\n",
      "Test Loss = 1.039266840179978\n",
      "Test Accuracy = 0.7326898868475148\n",
      "time: 235.63835406303406\n"
     ]
    }
   ],
   "source": [
    "import time\n",
    "start = time.time()\n",
    "\n",
    "model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])\n",
    "history = LossHistory() # 创建一个history实例\n",
    "\n",
    "model.fit(X_train, Y_train, epochs=100, batch_size=64, verbose=1, \n",
    "            validation_data=(X_test, Y_test),callbacks=[history])\n",
    "\n",
    "preds_train = model.evaluate(X_train, Y_train)\n",
    "print(\"Train Loss = \" + str(preds_train[0]))\n",
    "print(\"Train Accuracy = \" + str(preds_train[1]))\n",
    "\n",
    "preds_test  = model.evaluate(X_test, Y_test)\n",
    "print(\"Test Loss = \" + str(preds_test[0]))\n",
    "print(\"Test Accuracy = \" + str(preds_test[1]))\n",
    "\n",
    "\n",
    "end = time.time()\n",
    "print(\"time:\",end-start)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7fdabc7d06a0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "history.loss_plot('epoch')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.4"
  },
  "toc": {
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": "block",
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
